#include "ui_bipedwidget.h"

#include "script/scripthelper.h"
#include "script/write_lua.h"
#ifdef _ENABLE_LUABIND
#include <luabind/luabind.hpp>
#include <luabind/copy_policy.hpp>
#endif // _ENABLE_LUABIND

#include "util/timer.h"		    // Needs to come in early
#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging

#include <cassert>

using namespace ui;


UIBipedWidget::UIBipedWidget(UIWidget* pParent, const std::string& Name) : UIWidget(pParent, Name),
	m_BipedOffset(0.0f, 0.0f),
	m_BipedScale(1.0f),
	m_CenterBiped(false),
	m_HideBiped(false),
	m_PauseBiped(false),
	m_UpdateBiped(true)
{
	m_Type = WT_BIPED;
}

UIBipedWidget::~UIBipedWidget()
{
}

bool		UIBipedWidget::Load(LuaPlus::LuaObject& _LObj)
{
	using namespace script;

	UIWidget::Load(_LObj);

	std::string BipedAnim	= ScriptHelper::GetTableString(_LObj, "Biped", "");
	m_BipedOffset			= ScriptHelper::GetTableVec2(_LObj, "BipedOffset", math::Vec2(0.0f, 0.0f));
	m_BipedScale			= ScriptHelper::GetTableFloat(_LObj, "BipedScale", 1.0f);
	m_CenterBiped			= ScriptHelper::GetTableInt(_LObj, "CenterBiped", 0) ? true : false;

	SetBiped(BipedAnim);
	return true;
}

bool		UIBipedWidget::Tick(float dt)
{
	if (UIWidget::Tick(dt))
	{
		if (!m_PauseBiped)
			m_Biped.Tick(dt);

		if (!m_HideBiped && !m_UpdateBiped)
		{
			// if ((m_PrevPos != GetPosition()) || (m_PrevSize != GetSize()))
			// why is == and != not defined?
			const math::Vec2 Pos = GetPosition();
			const math::Vec2 Size = GetSize();
			if ((m_PrevPos.x != Pos.x) || (m_PrevPos.y != Pos.y) || (m_PrevSize.x != Size.x) || (m_PrevSize.y != Size.y))
			{
				SetCacheDirty();
			}
		}

		return true;
	}
	return false;
}

bool		UIBipedWidget::Render(bool Force)
{
	if (UIWidget::Render(Force))
	{
		if (m_HideBiped) return true;
		if (m_UpdateBiped)
		{
			// calculate biped position before rendering
			const math::Vec2 BoxPos = GetPosition();
			const math::Vec2 BoxSize = GetSize();

			// biped scaling
			if (m_BipedScale > 0.0f)
			{
				m_Biped.OBJECT_SCALE = m_BipedScale;
			}
			else
			{
				// auto-size the biped to widget -- requires use of dodgy sizes
				m_Biped.OBJECT_SCALE = 1.0f;
				if ((BoxSize.x > 0.0f) && (BoxSize.y > 0.0f)) // avoid division by zero
				{
					math::Vec2 ExtMin, ExtMax, SprExtMin, SprExtMax, Size;

					m_Biped.GetExtents(ExtMin, ExtMax);
					m_Biped.GetSpriteExtents(SprExtMin, SprExtMax);

					Size.x = UTIL_HIGH(ExtMax.x - ExtMin.x, SprExtMax.x - SprExtMin.x);
					Size.y = UTIL_HIGH(ExtMax.y - ExtMin.y, SprExtMax.y - SprExtMin.y);

					m_Biped.OBJECT_SCALE = UTIL_LOW(Size.x / BoxSize.x, Size.y / BoxSize.y);
				}
				else
					m_Biped.OBJECT_SCALE = 1.0f;
			}

			// biped positioning
			if (m_CenterBiped)
			{
				// auto-center the biped to widget -- also requires use of dodgy sizes
				if ((BoxSize.x > 0.0f) && (BoxSize.y > 0.0f)) // avoid division by zero
				{
					// can't reuse size data from above, may have changed due to object scale
					math::Vec2 ExtMin, ExtMax, SprExtMin, SprExtMax, Size;

					m_Biped.GetExtents(ExtMin, ExtMax);
					m_Biped.GetSpriteExtents(SprExtMin, SprExtMax);

					Size.x = UTIL_HIGH(ExtMax.x - ExtMin.x, SprExtMax.x - SprExtMin.x);
					Size.y = UTIL_HIGH(ExtMax.y - ExtMin.y, SprExtMax.y - SprExtMin.y);

					m_Biped.SetPos(BoxPos + math::Vec2(0.5f * BoxSize.x, 0.5f * (BoxSize.y + Size.y)));
				}
			}
			else
				m_Biped.SetPos(BoxPos + math::Vec2(0.5f * BoxSize.x, BoxSize.y));

			m_UpdateBiped = false;
			m_PrevPos = BoxPos;
			m_PrevSize = BoxSize;
		}

		m_Biped.Render(m_BipedOffset);
		return true;
	}
	return false;
}


UIWidget*	UIBipedWidget::GetClone()
{
	UIBipedWidget* pBiped = new UIBipedWidget(m_pParent, GetCloneName(m_Name));
	FillCloneInfo( (UIWidget*)pBiped );

	pBiped->m_BipedOffset	= m_BipedOffset;
	pBiped->m_BipedScale	= m_BipedScale;
	pBiped->m_CenterBiped	= m_CenterBiped;
	pBiped->m_HideBiped		= m_HideBiped;
	pBiped->m_PauseBiped	= m_PauseBiped;

	pBiped->SetBiped( m_Biped.GetAnimation() );
	return pBiped;
}

void		UIBipedWidget::SetBiped(const std::string& Anim)
{
	if (!Anim.empty())
	{
		m_Biped.SetAnimation(Anim);
		m_Biped.LoadDefaults();
		SetCacheDirty();
	}
}

bool		UIBipedWidget::ExportSpecificsToFile(script::WriteLua*	pWL)
{
	pWL->WritePair( "Biped",		m_Biped.GetAnimation() );
	pWL->WritePair( "BipedOffset",	m_BipedOffset );
	pWL->WritePair( "BipedScale",	m_BipedScale );
	pWL->WritePair( "CenterBiped",	(int)(m_CenterBiped ? 1 : 0));

	return true;
}


void		UIBipedWidget::Register(LuaPlus::LuaState* _pScript)
{
#ifdef _ENABLE_LUABIND
	// TODO: register script functions
	
	using namespace luabind;	
	lua_State * L = _pScript->GetCState ( );

	module(L)
    [
		luabind::class_<UIBipedWidget, UIWidget >( "BipedWidget" )	
		.def( "GetBipedOffset",			&UIBipedWidget::GetBipedOffset,		copy(result) )
		.def( "SetBipedOffset",			&UIBipedWidget::SetBipedOffset)
		.def( "GetBipedScale",			&UIBipedWidget::GetBipedScale)
		.def( "SetBipedScale",			&UIBipedWidget::SetBipedScale)
		.def( "GetIsCentered",			&UIBipedWidget::GetIsCentered)
		.def( "SetIsCentered",			&UIBipedWidget::SetIsCentered)
		.def( "GetBipedHidden",			&UIBipedWidget::GetBipedHidden)
		.def( "SetBipedHidden",			&UIBipedWidget::SetBipedHidden)
		.def( "GetBipedPaused",			&UIBipedWidget::GetBipedPaused)
		.def( "SetBipedPaused",			&UIBipedWidget::SetBipedPaused)
	];
#endif // _ENABLE_LUABIND
}
